package com.livestocksolutions.ui;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.Arrays;
import java.util.Collections;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;

import com.livestocksolutions.LivestockSolutions;
import com.livestocksolutions.Location;
import com.livestocksolutions.Observation;
import com.livestocksolutions.Paddock;
import com.livestocksolutions.util.Comparators;
import com.livestocksolutions.util.JDatePickerDate;
import com.livestocksolutions.util.Table;

/**
 * Display details relating to any Location, or a particular Location.
 * @author Ken DeVries
 * @author Adam Parr
 * 
<<<<<<< HEAD
 * @.modified 19 March 2013
=======
 * @.modified 13 March 2013
>>>>>>> branch 'master' of https://parr.adam@code.google.com/p/livestocksolutionscattlemanagementsystem/
 */
public class LocationPanel extends JPanel implements TabbedInterface {
	private static final long serialVersionUID = 1L;
	
	/**
	 * The initial view for this tab.
	 * Shows all Location that are in the system.
	 */
	public static final int LOCATION_LIST = 0;
	/**
	 * To create a new Location.
	 */
	public static final int VIEW_NEW_LOCATION=1;
	/**
	 * To view a Location details.
	 */
	public static final int VIEW=2;
	/**
	 * To view a Location details, showing all Observations.
	 */
	public static final int VIEW_OBSERVATION=3;

	/**
	 * Sort the Location list by name.
	 */
	protected final int LIST_ORDER_NAME = 0;
	
	/**
	 * Sort the observation list by Creation Date.
	 */
	protected final int LIST_ORDER_DATE = 1;
	/**
	 * Sort the observation list by using the Priority.
	 */
	protected final int LIST_ORDER_PRIORITY = 0;

	
	/**
	 * Order the Location list.
	 * @see #LIST_ORDER_NAME
	 */
	protected int orderLocationListBy = LIST_ORDER_NAME;
	
	/**
	 * The items Observation list order method.
	 * @see #LIST_ORDER_DATE
	 * @see #LIST_ORDER_PRIORITY
	 */
	protected int orderObservationListBy = LIST_ORDER_DATE;
	
	/**
	 * The sort direction. Ascending : 1, Descending -1;
	 */
	protected int orderLocationHighToLow = 1, orderObservationHighToLow = 1;
	
	/**
	 * Determine if the editable details of a Paddock is editable.
	 */
	protected boolean edit = false;
	
	/**
	 * The current view.
	 * 
	 * @see #LOCATION_LIST
	 * @see #VIEW_NEW_LOCATION
	 * @see #VIEW
	 * @see #VIEW_OBSERVATION
	 */
	private int viewing = -1;
	
	/**
	 * The ID of the Location we are Viewing.
	 */
	protected long locationViewID = 0;
	
	protected final JPanel panel = new JPanel();
	
	/**
	 * The Panel where the innerlist for a particular item will rest.
	 */
	protected JTabbedPane jisp = new JTabbedPane();
	protected final JPanel observationsListPanel = new JPanel();
	
	protected JTextField txtName = new JTextField();
	protected JTextArea txtDescription = new JTextArea();
	
	/**
	 * Constructor
	 */
	public LocationPanel(){
		JScrollPane jsp = new JScrollPane();
		setLayout(new BorderLayout(0, 0));
		jsp.setViewportView(panel);
		jsp.setViewportBorder(BorderFactory.createEmptyBorder());

		add(jsp);
		panel.setLayout(new BorderLayout(10, 10));

		AdjustmentListener al = new AdjustmentListener(){
			@Override
			public void adjustmentValueChanged(AdjustmentEvent evt) {
				panel.repaint();
			}
		};
		jsp.getHorizontalScrollBar().addAdjustmentListener(al);
		jsp.getVerticalScrollBar().addAdjustmentListener(al);
	}
	
	@Override 
	public void displayPanel(){
		int panel = viewing;
		if(viewing==LOCATION_LIST) {
			viewing=-1;
			panel = LOCATION_LIST;
		}
		displayPanel(panel);
	}
	
	/**
	 * @see #LOCATION_LIST
	 * @see #VIEW_NEW_LOCATION
	 * @see #VIEW
	 * @see #VIEW_OBSERVATION
	 */
	@Override
	public void displayPanel(int panel){
		switch (panel){
			case LOCATION_LIST:
				if(viewing!=LOCATION_LIST){
					createHomePanel();
				}
				break;
			case VIEW_NEW_LOCATION:
				if(viewing!=VIEW_NEW_LOCATION){
					createLocationPanel(-1);
				}
				break;
			case VIEW:
			case VIEW_OBSERVATION:
				createLocationPanel(locationViewID);
				break;
			default :
				createHomePanel();
		}
	}
	
	/**
	 * Create the list of Locations to chose from.
	 */
	private void createHomePanel(){
		viewing = LOCATION_LIST;
		locationViewID=0;
		panel.setLayout(new BorderLayout(0, 0));
		
		final int NAME	 	= 0;
		final int DESC		= 1;
		
		final Table locationPanel = new Table("Locations",false,
			"Name","Description");
		locationPanel.setEmptyMessage("There are no Locations to show.");
		
		new Thread(){
			@Override
			public void run(){
				while(!LivestockSolutions.isReady()){
					try {
						sleep(500);
					} catch (InterruptedException e) {}
					if(LivestockSolutions.close){
						return;
					}
				}
				
				locationPanel.setHeaderOrderedBy(orderLocationListBy==LIST_ORDER_NAME?NAME:NAME, orderLocationHighToLow==1);
				locationPanel.setHeaderClickable(DESC, false);
				locationPanel.addHeaderMouseListener(NAME, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderLocationHighToLow = orderLocationHighToLow*(orderLocationListBy==LIST_ORDER_NAME?-1:1);
						orderLocationListBy = LIST_ORDER_NAME;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Location[] lList = LivestockSolutions.getOnlyLocations();
				Arrays.sort(lList, Comparators.locationComparatorName);
				
				for(int x=0; x<lList.length; x++){
					String subComment = lList[x].getDescription();
					if(lList[x].getDescription().length()>97){
						subComment = lList[x].getDescription().substring(0,97)+"...";
					}
					locationPanel.addRow(
						new JLabel(lList[x].getName()),
						new JLabel(subComment));
					
					final long id = lList[x].getID();
					locationPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(createLocationPanel(id)){
								// Show Location not found message?
							}
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		panel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		
		JButton btnNewLocation = new JButton("New Location");
		btnNewLocation.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				createLocationPanel(-1L);
			}
		});
		buttonPanel.add(btnNewLocation);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(locationPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		panel.repaint();
	}
	
	/**
	 * Show the details for this Location with the given ID
	 * @param locationID The internal Id that identifies this Location
	 * @return <tt>true</tt> If a Location with the Id exists and was shown, <tt>false</tt> otherwise.
	 */
	public boolean createLocationPanel(final long locationID){
		final Location p = LivestockSolutions.getLocationByID(locationID);
		
		if(p instanceof Paddock){
			MainFrame.getInstance().showPaddock(locationID);
			return false;
		}
		if(locationViewID != locationID){
			viewing=VIEW;
			locationViewID = locationID;
			if(jisp.getParent()!=null)
				jisp.getParent().remove(jisp);
			jisp = new JTabbedPane();
			
			edit=false;
			txtName.setText("-1");
		}

		panel.setLayout(new BorderLayout(10, 10));
		panel.removeAll();
		
		JButton btnHome = new JButton("Location List");
		btnHome.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=false;
				txtName.setText("-1");
				viewing=-1;

				displayPanel(LOCATION_LIST);
			}
		});
		
		JPanel panel_1 = new JPanel();
		JPanel flowPanel = new JPanel();
		flowPanel.add(panel_1);
		
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10, 10));
		container.add(flowPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		
		JPanel buttonMenuLeft = new JPanel();
		JPanel buttonMenuRight = new JPanel();
		((FlowLayout)buttonMenuLeft.getLayout()).setAlignment(FlowLayout.LEFT);
		((FlowLayout)buttonMenuRight.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonMenuLeft.add(btnHome);
		
		if(p!=null || locationID==-1){
			String name="";
			String desc = "";
			String stu = "";

			boolean refresh=false;
			if(!txtName.getText().equals("-1")){
				refresh=true;
			}
			
			if(p!=null){
				name = p.getName();
				desc = p.getDescription();
			}else{
				if(locationID==-1){
					edit=true;
				}
			}
			
			if(!refresh){
				jisp.setOpaque(false);
				jisp.setBorder(new EmptyBorder(0,0,0,0));
				jisp.addTab("Observations",MainFrame.scale(MainFrame.getImageIcon(MainFrame.OBSERVATION_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), observationsListPanel);
				jisp.addMouseListener(new MouseListener(){
					@Override public void mouseClicked(MouseEvent e) {}
					@Override public void mousePressed(MouseEvent e) {
						new Thread(){@Override
						public void run(){
							if(jisp.getSelectedComponent()==observationsListPanel)
								createObservationsPanel(locationID);
						}}.start();
					}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				jisp.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
				jisp.setAutoscrolls(true);
				
				jisp.setBorder(new EmptyBorder(0,0,0,0));
			}			
			panel.add(jisp,BorderLayout.CENTER);
			panel_1.setLayout(new BorderLayout(5, 0));
			
			JPanel panel_2 = new JPanel();
			panel_1.add(panel_2, BorderLayout.NORTH);
			panel_2.setLayout(new BorderLayout(5, 0));
			
			JPanel namePanel = new JPanel();
			panel_2.add(namePanel, BorderLayout.WEST);
			namePanel.setLayout(new BoxLayout(namePanel, BoxLayout.PAGE_AXIS));
			
			JPanel paddockNamePanel = new JPanel();
			namePanel.add(paddockNamePanel);
			paddockNamePanel.setLayout(new BorderLayout(0, 0));
	
			paddockNamePanel.add(new JLabel("Name:"));
			
			JPanel paddockAreaPanel = new JPanel();
			namePanel.add(paddockAreaPanel);
			paddockAreaPanel.setLayout(new BorderLayout(0, 0));
			
			JPanel valuePanel = new JPanel();
			panel_2.add(valuePanel, BorderLayout.CENTER);
			valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS));
			
			txtName.setText(refresh?txtName.getText():name);
			txtName.setEditable(edit);
			valuePanel.add(txtName);
			txtName.setColumns(10);
			
			JPanel paddockDescPanel = new JPanel();
			panel_1.add(paddockDescPanel, BorderLayout.CENTER);
			paddockDescPanel.setLayout(new BorderLayout(0, 5));
	
			paddockDescPanel.add(new JLabel("Description:"), BorderLayout.WEST);
			
			txtDescription.setText(refresh?txtDescription.getText():desc);
			txtDescription.setEditable(edit);
			txtDescription.setRows(3);
			paddockDescPanel.add(txtDescription, BorderLayout.SOUTH);
			
			JPanel safeToUsePanel = new JPanel();
			JLabel lblSafeToUse = new JLabel(stu);
			safeToUsePanel.add(lblSafeToUse);
			panel_1.add(safeToUsePanel, BorderLayout.SOUTH);

			if(viewing == VIEW_OBSERVATION || viewing == VIEW){
				jisp.setSelectedComponent(observationsListPanel);
				createObservationsPanel(locationID);
			}
			
			JButton btnCancel = new JButton(locationViewID!=-1?"Cancel":"Clear");
			btnCancel.setVisible(edit);
			btnCancel.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					edit=false;
					txtName.setText("-1");
					displayPanel(viewing);
				}
			});
			
			JButton btnCreateSave = new JButton(locationViewID==-1?"Create":edit?"Save":"Edit");
			btnCreateSave.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					if(edit){
						Location l = LivestockSolutions.getLocationByID(locationViewID);
						if(l==null){
							l = new Location();
						}
						l.setName(txtName.getText());
						l.setDescription(txtDescription.getText());
						
						if(LivestockSolutions.addLocation(l)){
							LocationPanel.this.locationViewID=l.getID();
							txtName.setText("-1");
							edit=!edit;
						}else{
							JOptionPane.showMessageDialog(MainFrame.getInstance(),"Failed to save changes.","Failed to Save", JOptionPane.OK_OPTION);
						}
					}else{
						txtName.setText("-1");
						edit=!edit;
					}
					displayPanel(viewing);
				}
			});
			
			buttonMenuRight.add(btnCreateSave);
			buttonMenuRight.add(btnCancel);
			
			JPanel buttonMenu = new JPanel();
			buttonMenu.setLayout(new BorderLayout());
			buttonMenu.add(buttonMenuLeft,BorderLayout.WEST);
			buttonMenu.add(buttonMenuRight,BorderLayout.EAST);
			container.add(buttonMenu,BorderLayout.NORTH);
		}else{
			panel.removeAll();
			panel.setLayout(new BorderLayout(10, 10));

			JPanel flow =new JPanel();
			JLabel label = new JLabel("No Such Location can be found with the given internal id: "+locationID+".");
			flow.add(label);
			panel.add(flow, BorderLayout.NORTH);
			
			return false;
		}
		
		validate();
		
		return true;
	}
	
	/**
	 * Create a list of observations that belong to this Location.
	 * @param locationID The long ID value that represents the Location to show the Observations for.
	 */
	private void createObservationsPanel(final long locationID){
		viewing = VIEW_OBSERVATION;
		observationsListPanel.setLayout(new BorderLayout());
		
		final int DATE 		= 0;
		final int DESCRIPTION 	= 1;
		final int PRIORITY 	= 2;
		
		final Table observationPanel = new Table("Observations",false,
			"Date","Description","Priority");
		observationPanel.setEmptyMessage("There are no observations to show.");
		
		final Location l = LivestockSolutions.getLocationByID(locationID);
		new Thread(){
			@Override
			public void run(){
				observationPanel.setHeaderClickable(DESCRIPTION, false);
				observationPanel.setHeaderOrderedBy(orderObservationListBy==LIST_ORDER_DATE?DATE:orderObservationListBy==LIST_ORDER_PRIORITY?PRIORITY:DATE, orderObservationHighToLow==1);
				observationPanel.addHeaderMouseListener(DATE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderObservationHighToLow = orderObservationHighToLow*(orderObservationListBy==LIST_ORDER_DATE?-1:1);
						orderObservationListBy = LIST_ORDER_DATE;
						createObservationsPanel(locationID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				observationPanel.addHeaderMouseListener(PRIORITY, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderObservationHighToLow = orderObservationHighToLow*(orderObservationListBy==LIST_ORDER_PRIORITY?-1:1);
						orderObservationListBy = LIST_ORDER_PRIORITY;
						createObservationsPanel(locationID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Observation[] oList = l!=null?l.getObservations():new Observation[]{};
				
				Arrays.sort(oList, 
					orderObservationListBy==LIST_ORDER_DATE?
							orderObservationHighToLow==1?Comparators.observationComparatorDate:Collections.reverseOrder(Comparators.observationComparatorDate)
					:orderObservationHighToLow==1?Comparators.observationComparatorPriority:Collections.reverseOrder(Comparators.observationComparatorPriority));

				for(int x=0; x<oList.length; x++){
					observationPanel.addRow(
						new JLabel(JDatePickerDate.format(oList[x].getDate())),
						new JLabel(oList[x].getComment()),
						new JLabel(Observation.getPriorityString(oList[x].getPriority())));
					
					final Observation o = oList[x];
					
					observationPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							new ObservationFrame(l,o,"Location: "+l.getName()).addWindowListener(new WindowListener(){
								@Override public void windowOpened(WindowEvent e) {}
								@Override
								public void windowClosing(WindowEvent e) {
									// Refresh Page
									if(viewing==VIEW_OBSERVATION && locationViewID==locationID){
										createObservationsPanel(locationID);
									}
								}
								@Override public void windowClosed(WindowEvent e) {}
								@Override public void windowIconified(WindowEvent e) {}
								@Override public void windowDeiconified(WindowEvent e) {}
								@Override public void windowActivated(WindowEvent e) {}
								@Override public void windowDeactivated(WindowEvent e) {}
							});
						}
						@Override public void mousePressed(MouseEvent e) { }
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		final JButton btnAddObservation = new JButton("Add Observation");
		btnAddObservation.setEnabled(l!=null);
		btnAddObservation.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				ObservationFrame of =new ObservationFrame(l,null," Location: "+l.getName());
				observationPanel.addRow(null,new JLabel("<New Observation>"),null);
				btnAddObservation.setEnabled(false);
				observationPanel.validate();
				panel.validate();
				of.addWindowListener(new WindowListener(){
					@Override
					public void windowClosing(WindowEvent e) {
						// Refresh Page
						if(viewing==VIEW_OBSERVATION && LocationPanel.this.locationViewID==locationViewID){
							createObservationsPanel(locationViewID);
						}
					}
					@Override public void windowOpened(WindowEvent e) {}
					@Override public void windowClosed(WindowEvent e) {}
					@Override public void windowIconified(WindowEvent e) {}
					@Override public void windowDeiconified(WindowEvent e) {}
					@Override public void windowActivated(WindowEvent e) {}
					@Override public void windowDeactivated(WindowEvent e) {}
				});
			}
		});

		observationsListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddObservation);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(observationPanel,BorderLayout.CENTER);
		observationsListPanel.add(container, BorderLayout.NORTH);
		panel.validate();
		
		jisp.setSelectedComponent(observationsListPanel);
	}

	@Override
	public long getID() {
		return locationViewID;
	}
}
